#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_ota_ops.h"
#include "esp_http_client.h"
#include "esp_https_ota.h"
#include "esp_crt_bundle.h"
#include "protocol_examples_common.h"
#include "string.h"
#include "esp_timer.h"

#include "Datapara.h"
#include "OTA.h"
#include "WiFiIno_flash.h"

EventGroupHandle_t ota_event_group;  //ota事件组句柄

static const char *TAG = "simple_ota_example";

#define HASH_LEN 32
#define OTA_URL_SIZE 256

esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
    static int64_t start_time = 0;
    static int64_t total_bytes_downloaded = 0;

    switch (evt->event_id) {
    case HTTP_EVENT_ERROR:
        ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
        break;
    case HTTP_EVENT_ON_CONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_CONNECTED");
        start_time = esp_timer_get_time();        //记录开始时间
        break;
    case HTTP_EVENT_HEADER_SENT:
        ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
        break;
    case HTTP_EVENT_ON_HEADER:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
        break;
    case HTTP_EVENT_ON_DATA:

        xEventGroupSetBits(ota_event_group, OTA_IN_PROGRESS);   //设置ota事件组OTA_IN_PROGRESS位置位

        total_bytes_downloaded += evt->data_len;
        int64_t current_time = esp_timer_get_time();
        if (current_time - start_time >= 1000000) { // 每 1 秒计算一次下载速度
            double elapsed_time = (current_time - start_time) / 1000000.0;
            double download_speed = total_bytes_downloaded / elapsed_time;
            ESP_LOGI(TAG, "Download speed: %.2f KB/s", download_speed / 1024);    //打印下载速度
            start_time = current_time;
        }
        ESP_LOGD(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
        break;
    case HTTP_EVENT_ON_FINISH:
        ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
        break;
    case HTTP_EVENT_DISCONNECTED:
        ESP_LOGD(TAG, "HTTP_EVENT_DISCONNECTED");
        break;
    case HTTP_EVENT_REDIRECT:
        ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
        break;
    }
    return ESP_OK;
}


static void print_sha256(const uint8_t *image_hash, const char *label)
{
    char hash_print[HASH_LEN * 2 + 1];
    hash_print[HASH_LEN * 2] = 0;
    for (int i = 0; i < HASH_LEN; ++i) {
        sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
    }
    ESP_LOGI(TAG, "%s %s", label, hash_print);
}



static void get_sha256_of_partitions(void)
{

    uint8_t sha_256[HASH_LEN] = { 0 };
    esp_partition_t partition;

    // get sha256 digest for bootloader
    partition.address   = ESP_BOOTLOADER_OFFSET;
    partition.size      = ESP_PARTITION_TABLE_OFFSET;
    partition.type      = ESP_PARTITION_TYPE_APP;
    esp_partition_get_sha256(&partition, sha_256);
    print_sha256(sha_256, "SHA-256 for bootloader: ");

    // get sha256 digest for running partition
    esp_partition_get_sha256(esp_ota_get_running_partition(), sha_256);
    print_sha256(sha_256, "SHA-256 for current firmware: ");
}


void simple_ota_example_task(void *pvParameter)
{
    // 获取分区的SHA256哈希值
    get_sha256_of_partitions();
    
    // 打印日志，表明OTA示例任务正在启动
    ESP_LOGI(TAG, "Starting OTA example task");

    // 配置HTTP客户端
    esp_http_client_config_t config = {
        // 设置OTA更新的URL
        .url = AWS_OTA_Ino.url,
        // 附加证书捆绑包
        .crt_bundle_attach = esp_crt_bundle_attach,

        // 设置HTTP事件处理函数
        .event_handler = _http_event_handler,
        // 启用保持连接
        .keep_alive_enable = true,
    };

    // 配置HTTPS OTA
    esp_https_ota_config_t ota_config = {
        .http_config = &config,
    };


    ESP_LOGI(TAG, "Attempting to download update from %s", config.url);

    esp_err_t ret = esp_https_ota(&ota_config);
    if (ret == ESP_OK) {
        OTA_FINISH_OR_FAIL = 1;
        xEventGroupSetBits(ota_event_group, OTA_SUCCEEDED);   //设置ota事件组OTA_FINISH位置位
        
        write_nvs_byte(NVS_OTACfgStatus_NAMESPACE, NVS_OTACfgStatus, &OTA_FINISH_OR_FAIL);  //存储OTA_FINISH_OR_FAIL的值到NVS中

         xEventGroupWaitBits(ota_event_group, OTA_UPDATA_FINISH , pdTRUE, pdFALSE, portMAX_DELAY);  //等待OTA_UPDATA_FINISH位置位，OTA “success” 信息上传云端完成后再重启
        ESP_LOGI(TAG, "OTA Succeed, Rebooting...");

        esp_restart();   //重启
    } else {
        ESP_LOGE(TAG, "Firmware upgrade failed");
    }
    while (1) {
        ESP_LOGI(TAG, "Starting OTA example task正在运行中...");
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}


